﻿
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class PrefabLightmapData : MonoBehaviour
{
    [System.Serializable]
    struct RendererInfo
    {
        public Renderer renderer;
        public int lightmapIndex;
        public Vector4 lightmapScaleOffset;
    }
    [System.Serializable]
    struct TerrainRendererInfo
    {
        public Terrain terrain;
        public int lightmapIndex;
        public Vector4 lightmapScaleOffset;
    }

    [System.Serializable]
    struct LightmapInfo
    {
        public Texture2D lightmapFar;
        public Texture2D lightmapNear;
        public string FarName;
        public string NearName;
    }

    [SerializeField]
    RendererInfo[] m_RendererInfo;
    [SerializeField]
    LightmapInfo[] m_Lightmaps;
    [SerializeField]
    TerrainRendererInfo[] m_TerrainRendererInfo;


    void OnEnable()
    {
        //if (m_RendererInfo == null || m_RendererInfo.Length == 0)
        //    return;

        //方式一
        var lightmaps = LightmapSettings.lightmaps;
        var combinedLightmaps = new LightmapData[lightmaps.Length + m_Lightmaps.Length];

        lightmaps.CopyTo(combinedLightmaps, 0);
        for (int i = 0; i < m_Lightmaps.Length; i++)
        {
            combinedLightmaps[i + lightmaps.Length] = new LightmapData();
            if (m_Lightmaps[i].lightmapFar != null)
            {
                combinedLightmaps[i + lightmaps.Length].lightmapFar = m_Lightmaps[i].lightmapFar;
            }
            if (m_Lightmaps[i].lightmapNear != null)
            {
                combinedLightmaps[i + lightmaps.Length].lightmapNear = m_Lightmaps[i].lightmapNear;
            }
        }

        ApplyRendererInfo(m_RendererInfo, lightmaps.Length);
        ApplyTerrainRendererInfo(m_TerrainRendererInfo, lightmaps.Length);

        LightmapSettings.lightmaps = combinedLightmaps;

        ////方式二
        //var combinedLightmaps = new LightmapData[m_Lightmaps.Length];
        //for (int i = 0; i < m_Lightmaps.Length; i++)
        //{
        //    combinedLightmaps[i] = new LightmapData();
        //    if (m_Lightmaps[i].lightmapFar != null)
        //    {
        //        combinedLightmaps[i].lightmapFar = m_Lightmaps[i].lightmapFar;
        //    }
        //    if (m_Lightmaps[i].lightmapNear != null)
        //    {
        //        combinedLightmaps[i].lightmapNear = m_Lightmaps[i].lightmapNear;
        //    }
        //}

        //ApplyRendererInfo(m_RendererInfo, 0);
        //ApplyTerrainRendererInfo(m_TerrainRendererInfo, 0);

        //LightmapSettings.lightmaps = combinedLightmaps;

    }


    static void ApplyRendererInfo(RendererInfo[] infos, int lightmapOffsetIndex)
    {
        for (int i = 0; i < infos.Length; i++)
        {
            var info = infos[i];
            if (info.renderer != null)
            {
                info.renderer.lightmapIndex = info.lightmapIndex + lightmapOffsetIndex;
                info.renderer.lightmapScaleOffset = info.lightmapScaleOffset;
            }

        }
    }

    static void ApplyTerrainRendererInfo(TerrainRendererInfo[] infos, int lightmapOffsetIndex)
    {
        for (int i = 0; i < infos.Length; i++)
        {
            var info = infos[i];
            if (info.terrain != null)
            {
                info.terrain.lightmapIndex = info.lightmapIndex + lightmapOffsetIndex;
                info.terrain.lightmapScaleOffset = info.lightmapScaleOffset;
            }
        }
    }

#if UNITY_EDITOR

    [UnityEditor.MenuItem("Assets/Bake Prefab Lightmaps")]
    static void GenerateLightmapInfo()
    {
        if (UnityEditor.Lightmapping.giWorkflowMode != UnityEditor.Lightmapping.GIWorkflowMode.OnDemand)
        {
            Debug.LogError("ExtractLightmapData requires that you have baked you lightmaps and Auto mode is disabled.");
            return;
        }
        UnityEditor.Lightmapping.BakeAsync();
        Lightmapping.completed = OnCompleted;

    }

    [UnityEditor.MenuItem("Slg/记录光照信息到预制体")]
    static void OnCompleted()
    {
        PrefabLightmapData[] prefabs = FindObjectsOfType<PrefabLightmapData>();

        foreach (var instance in prefabs)
        {
            var gameObject = instance.gameObject;
            var rendererInfos = new List<RendererInfo>();
            var lightmaps = new List<LightmapInfo>();
            var terrainRendererInfo = new List<TerrainRendererInfo>();
            GenerateLightmapInfo(gameObject, rendererInfos, lightmaps, terrainRendererInfo);

            instance.m_RendererInfo = rendererInfos.ToArray();
            instance.m_Lightmaps = lightmaps.ToArray();
            instance.m_TerrainRendererInfo = terrainRendererInfo.ToArray();
            var targetPrefab = UnityEditor.PrefabUtility.GetPrefabParent(gameObject) as GameObject;
            if (targetPrefab != null)
            {
                //UnityEditor.Prefab
                UnityEditor.PrefabUtility.ReplacePrefab(gameObject, targetPrefab);
            }
        }
        //EditorUtility.ClearProgressBar();
    }

    static void GenerateLightmapInfo(GameObject root, List<RendererInfo> rendererInfos, List<LightmapInfo> lightmaps, List<TerrainRendererInfo> terrainRendererInfos)
    {
        var renderers = root.GetComponentsInChildren<MeshRenderer>();
        var terrains = root.GetComponentsInChildren<Terrain>();
        int i = 0;
        foreach (MeshRenderer renderer in renderers)
        {
            i++;
            EditorUtility.DisplayProgressBar("序列化网格光照信息", "正在序列化网格光照信息。。。。", 1f * i / renderers.Length);
            if (renderer.lightmapIndex != -1)
            {
                RendererInfo info = new RendererInfo();
                info.renderer = renderer;
                info.lightmapScaleOffset = renderer.lightmapScaleOffset;
                info.lightmapIndex = renderer.lightmapIndex;
                rendererInfos.Add(info);

                Texture2D lightmapFar = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapFar;
                Texture2D lightmapNear = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapNear;
                LightmapInfo light = new LightmapInfo();
                light.lightmapFar = lightmapFar;
                light.lightmapNear = lightmapNear;
                if (lightmapFar != null)
                {
                    light.FarName = lightmapFar.name;
                }
                if (lightmapNear != null)
                    light.NearName = lightmapNear.name;

                if (lightmaps.Count == 0)
                {
                    lightmaps.Add(light);
                }
                else
                {
                    bool add = true;
                    for (int k = 0; k < lightmaps.Count; k++)
                    {
                        if (lightmaps[k].FarName == light.FarName)
                        {
                            add = false;
                            break;
                        }
                    }
                    if (add) lightmaps.Add(light);
                }
                // info.lightmapIndex = lightmaps.IndexOf(light);
                // if (info.lightmapIndex == -1)
                // {
                //     info.lightmapIndex = lightmaps.Count;
                //     lightmaps.Add(light);
                // }

            }
        }
        EditorUtility.ClearProgressBar();

        int j = 0;
        foreach (var terrain in terrains)
        {
            j++;
            EditorUtility.DisplayProgressBar("序列化地形光照信息", "正在序列化地形光照信息。。。。", 1f * i / terrains.Length);
            if (terrain.lightmapIndex != -1)
            {
                TerrainRendererInfo info = new TerrainRendererInfo();
                info.terrain = terrain;
                info.lightmapScaleOffset = terrain.lightmapScaleOffset;
                info.lightmapIndex = terrain.lightmapIndex;
                terrainRendererInfos.Add(info);

                Texture2D lightmapFar = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapFar;
                Texture2D lightmapNear = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapNear;
                LightmapInfo light = new LightmapInfo();
                light.lightmapFar = lightmapFar;
                light.lightmapNear = lightmapNear;
                if (lightmapFar != null)
                {
                    light.FarName = lightmapFar.name;
                }
                if (lightmapNear != null)
                    light.NearName = lightmapNear.name;

                if (lightmaps.Count == 0)
                {
                    lightmaps.Add(light);
                }
                else
                {
                    bool add = true;
                    for (int k = 0; k < lightmaps.Count; k++)
                    {
                        if (lightmaps[k].FarName == light.FarName)
                        {
                            add = false;
                            break;
                        }
                    }
                    if (add) lightmaps.Add(light);
                }
                // info.lightmapIndex = lightmaps.IndexOf(light);
                // if (info.lightmapIndex == -1)
                // {
                //     info.lightmapIndex = lightmaps.Count;
                //     lightmaps.Add(light);
                // }

            }
        }
        EditorUtility.ClearProgressBar();
        lightmaps.Sort(new CompareLightmap());
        //if(terrains != null && terrains.lightmapIndex != -1)
        //{
        //    terrainRendererInfos.terrain = terrains;
        //    terrainRendererInfos.lightmapOffsetScale = terrains.lightmapScaleOffset;
        //    terrainRendererInfos.lightmapIndex = terrains.lightmapIndex;
        //    Texture2D lightmapFar2 = LightmapSettings.lightmaps[terrains.lightmapIndex].lightmapFar;
        //    Texture2D lightmapNear2 = LightmapSettings.lightmaps[terrains.lightmapIndex].lightmapNear;
        //    LightmapInfo light = new LightmapInfo();
        //    light.lightmapFar = lightmapFar2;
        //    light.lightmapNear = lightmapNear2;

        //    terrainRendererInfos.lightmapIndex = lightmaps.IndexOf(light);
        //    if (terrainRendererInfos.lightmapIndex == -1)
        //    {
        //        terrainRendererInfos.lightmapIndex = lightmaps.Count;
        //        lightmaps.Add(light);
        //    }
        //}


    }

    [UnityEditor.MenuItem("Assets/Recovery Prefab Lightmaps info")]
    static void RecoveryLightmapData()
    {
        PrefabLightmapData[] prefabs = FindObjectsOfType<PrefabLightmapData>();

        foreach (var instance in prefabs)
        {
            var gameObject = instance.gameObject;
            var rendererInfos = new List<RendererInfo>(instance.m_RendererInfo);
            var lightmaps = new List<LightmapInfo>(instance.m_Lightmaps);
            var terrainRendererInfo = new List<TerrainRendererInfo>(instance.m_TerrainRendererInfo);
            var renderers = gameObject.GetComponentsInChildren<MeshRenderer>();
            var terrains = gameObject.GetComponentsInChildren<Terrain>();

            var temp = new List<LightmapInfo>(lightmaps);
            temp.Sort(new CompareLightmap());
            Dictionary<int, int> index2indexMap = new Dictionary<int, int>();
            for (int ii = 0; ii < lightmaps.Count; ii++)
            {
                Predicate<LightmapInfo> predicate = (info) =>
                {
                    return info.lightmapFar.name == lightmaps[ii].lightmapFar.name;
                };
                int index = temp.FindIndex(predicate);
                index2indexMap.Add(ii, index);
            }

            int i = 0;
            foreach (RendererInfo renderInfo in instance.m_RendererInfo)
            {
                i++;
                EditorUtility.DisplayProgressBar("还原网格光照信息", "正在还原网格光照信息。。。。", 1f * i / renderers.Length);

                if (renderInfo.renderer != null)
                {
                    renderInfo.renderer.lightmapIndex = index2indexMap[renderInfo.lightmapIndex];
                    renderInfo.renderer.lightmapScaleOffset = renderInfo.lightmapScaleOffset;
                }

            }
            EditorUtility.ClearProgressBar();

            int j = 0;
            foreach (var terrainInfo in instance.m_TerrainRendererInfo)
            {
                j++;
                EditorUtility.DisplayProgressBar("还原地形光照信息", "正在还原地形光照信息。。。。", 1f * i / terrains.Length);
                if (terrainInfo.terrain != null)
                {
                    terrainInfo.terrain.lightmapIndex = index2indexMap[terrainInfo.lightmapIndex];
                    terrainInfo.terrain.lightmapScaleOffset = terrainInfo.lightmapScaleOffset;
                }
            }
            EditorUtility.ClearProgressBar();


            var targetPrefab = UnityEditor.PrefabUtility.GetPrefabParent(gameObject) as GameObject;
            if (targetPrefab != null)
            {
                //UnityEditor.Prefab
                UnityEditor.PrefabUtility.ReplacePrefab(gameObject, targetPrefab);
            }
        }
    }

#endif
    class CompareLightmap : IComparer<LightmapInfo>
    {
        public int Compare(LightmapInfo x, LightmapInfo y)
        {
            string[] numxs = x.lightmapFar.name.Split(new char[] { '-', '_' });
            int numx = Convert.ToInt32(numxs[1]);
            string[] numys = y.lightmapFar.name.Split(new char[] { '-', '_' });
            int numy = Convert.ToInt32(numys[1]);
            return numx.CompareTo(numy);
        }

    }


}